package com.novartis.nims.util;

import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;
import java.util.Iterator;

/**
 * Iterates over all non-directory files contained in some subdirectory of the 
 * current one.
 * 
 * Recursion into sub-directories happens dynamically during iteration.
 * TODO update to recurse during initialization so Exception can be thrown on unreadable directory.
 *
 * @author josh snyder, adapted from http://snippets.dzone.com/posts/show/3532
 */
public class RecursiveFileListIterator implements Iterator<File>
{
    private final FlatteningIterator flatteningIterator;
    
    public void remove() { } 
    
    public RecursiveFileListIterator(File file, FileFilter filter){
        this.flatteningIterator = new FlatteningIterator(new FileIterator(file, filter)); }
    
    public RecursiveFileListIterator(File file){
        this(file, null);}
    
    
    public boolean hasNext(){ 
        return flatteningIterator.hasNext();}
    
    public File next(){ 
        return (File)flatteningIterator.next();}
    
    
    /**
     * Iterator to iterate over all the files contained in a directory. It returns
     * a File object for non directories or a new FileIterator obejct for directories.
     * 
     * This will treat unreadable directories as empty directories. Iterator interface does
     * not allow Exceptions to be thrown, so we can't treat this as an error condition.
     * If we really want errors in such cases, we should iterate through a pre-constructed
     * list of Files, rather than constructing a list for each directory dynamically.
     */
    private static class FileIterator implements Iterator<Object>
    {
        private final Iterator<File> files;
        private final FileFilter filter;
        
        //TODO change so unchecked NPE is thrown on unreadable dir?
        FileIterator(File file, FileFilter filter) {
        	File[] fileList = file.listFiles(filter);
        	if (fileList == null) {
        		fileList = new File[0];
        	}
    		this.files = Arrays.asList(fileList).iterator();
            this.filter = filter;}
        
        public void remove() { }
        
        public Object next() {
            File next = this.files.next();
            
            if (next.isDirectory()) return new FileIterator(next, this.filter);
            else return next;}
        
        public boolean hasNext(){
            return this.files.hasNext();}       
    }
}